package red.mlz.console.controller.excel;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import red.mlz.console.annotations.VerifiedUser;
import red.mlz.module.listener.DynamicExcelListener;
import red.mlz.module.module.category.entity.Category;
import red.mlz.module.module.category.service.CategoryService;
import red.mlz.module.module.user.entity.User;
import red.mlz.module.utils.BaseUtils;
import red.mlz.module.utils.Response;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

@RestController
@Slf4j
public class ExcelController {

    @Autowired
    private CategoryService categoryService;

    @Autowired
    @Qualifier("exportTaskExecutor")
    private ExecutorService exportTaskExecutor;

    @RequestMapping("/excel/upload")
    public Response upload(@VerifiedUser User loginUser,
                           @RequestParam(name = "file") MultipartFile file,
                           @RequestParam(value = "headerRow", defaultValue = "0") int headerRow) {

        if (BaseUtils.isEmpty(loginUser)) {
            return new Response(1002);
        }
        System.out.println("开始处理文件：" + file.getOriginalFilename());
        try (InputStream inputStream = file.getInputStream()) {
            DynamicExcelListener listener = new DynamicExcelListener(headerRow);

            EasyExcel.read(inputStream)
                    .headRowNumber(headerRow)
                    .registerReadListener(listener)
                    .sheet()
                    .doRead();

            System.out.println("处理完成，结果数据：" + listener.getResult());
            return new Response(1001, listener.getResult());
        } catch (Exception e) {
            return new Response(4004, "文件上传失败" + e.getMessage());
        }
    }

    @RequestMapping("/categories/export")
    public void exportCategories(HttpServletResponse response) {
        try {
            response.setCharacterEncoding("UTF-8");
            setResponseHeaders(response);
            doExport(response.getOutputStream());
        } catch (Exception e) {
            handleExportError(response, e);
        }
    }

    private void setResponseHeaders(HttpServletResponse response) {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet; charset=UTF-8");
        response.setHeader("Content-Disposition", "attachment; filename=categories.xlsx");
    }

    private void doExport(ServletOutputStream outputStream) throws Exception {
        final int pageSize = 1000;
        long total = categoryService.getTotalCount();
        int totalPages = (int) ((total + pageSize - 1) / pageSize);

        try (ExcelWriter excelWriter = EasyExcel.write(outputStream, Category.class)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .build()) {

            WriteSheet writeSheet = EasyExcel.writerSheet("分类数据").build();

            List<CompletableFuture<List<Category>>> futures = new ArrayList<>();
            for (int page = 0; page < totalPages; page++) {
                final int currentPage = page;
                CompletableFuture<List<Category>> future = CompletableFuture.supplyAsync(
                        () -> categoryService.getByPage(currentPage, pageSize),
                        exportTaskExecutor
                );
                futures.add(future);
            }

            for (CompletableFuture<List<Category>> future : futures) {
                try {
                    List<Category> data = future.get(30, TimeUnit.SECONDS);
                    excelWriter.write(data, writeSheet);
                } catch (Exception e) {
                    log.error("导出数据时出错", e);
                }
            }
        }
    }

    private void handleExportError(HttpServletResponse response, Exception e) {
        try {
            if (!response.isCommitted()) {
                response.reset();
                response.setContentType("application/json; charset=UTF-8");
                response.setCharacterEncoding("UTF-8");
                response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
                String json = String.format(
                        "{\"code\":500,\"message\":\"%s\"}",
                        e.getMessage()
                );
                response.getWriter().write(json);
            } else {
                log.error("无法返回错误信息，响应已提交");
            }
        } catch (IOException ex) {
            log.error("处理导出异常失败", ex);
        }
    }
}
